#ifndef OFFSET_TABLE_H_
#define OFFSET_TABLE_H_
#include "config.h"
#include <map>
#include <string>
#include <unistd.h>
#include <stdio.h>
#include <vector>
#include <pthread.h>
#include <set>
#include "locking.h"
using namespace std;
class OffsetBlock;

void print_indent(FILE *out, int indent);
struct RowOffset {
	unsigned long long int offset; //offset from the beginning of the first row.
	unsigned long long int firstRow; //index of the first row.
	unsigned long long int lastRow; //index of the last row
	unsigned long long int numRows; //number of rows.
	unsigned long long int size; //size (in bytes) of the data that belongs to this rowoffset.
	RowOffset(long long int os, long long int fr, long long int lr, long long int nr, long long int sz) {
		offset = os;
		firstRow = fr;
		lastRow = lr;
		numRows = nr;
		size = sz;
	}
	RowOffset(const RowOffset& ro) {
		offset = ro.offset;
		numRows = ro.numRows;
		size = ro.size;
		firstRow = ro.firstRow;
		lastRow = ro.lastRow;
	}
	RowOffset& operator=(const RowOffset& ro) {
		if(this != &ro) {
			this->numRows = ro.numRows;
			this->size = ro.size;
			this->firstRow = ro.firstRow;
			this->offset = ro.offset;
			this->lastRow = ro.lastRow;
		}
		return *this;
	}
	void print(FILE* out, int indent) {
		print_indent(out, indent);
		fprintf(out, "<RowOffset>offset=%llu, firstRow=%llu, lastRow=%llu, numRows=%llu, size =%llu\n",
				offset, firstRow, lastRow, numRows, size);
	}
};

class OffsetTable {
public:
	static OffsetTable* Get(const string& table, bool read_table = false);
	RowOffset findRows(unsigned long long int offset, unsigned long long int size);
	void appendRow(unsigned long long int rowid, unsigned long long int size);
	static void rename(string from, string to) {
		SRLock _srl(offsetTablesLock);
		offsetTables[to]  = offsetTables[from];
		offsetTables.erase(from);
	}
	static void drop(string table) {
		SRLock _srl(offsetTablesLock);
		OffsetTable *t = offsetTables[table];
		offsetTables.erase(table);
		delete t;
	}
	void clear();
	unsigned long long int getSize();
	unsigned long long int getLastRow();
	void truncate(unsigned long long int rowid, unsigned long long int newSize);
	void print(FILE* index = NULL, int indent = 0);
	void updateRowSize(size_t rowid, size_t old_size, size_t new_size);
private:
	OffsetTable& operator=(const OffsetTable&);
	unsigned long long int size;	//size of this table in bytes.
	unsigned long long int numRows;
	unsigned long long int firstRow, lastRow;
	OffsetBlock *first, *last;
	vector<OffsetBlock*> offsetBlockList;
	//read stuff from the database.
	//this method can read the meta data, or rescan the entire db.
	void init(const string& table);	
	OffsetTable(const string& table, bool read_table);
	~OffsetTable();
	OffsetTable(const OffsetTable&);
	//map from offset to offsetblocks
	map<unsigned long long int, OffsetBlock*> offsetMap;
	static LOCK offsetTablesLock;
	static map<string, OffsetTable*> offsetTables;
	void addAutoIncColumn(const string& table);
	//LOCK lock;
	RWLOCK lock;
	char index_file[200];
};

#endif //OFFSET_TABLE_H_
